/*
 * Abstract superclass for all pieces that involve networking and would like randomness to be
 * synced across all parties.
 */
NetworkPiece {
	var <>name, <>ip, <>port;
	var randomSeed, <>headGroup, <>serverRandSeed, groupAddress, randSyncResponder;
	
	*new {|name,ip,port|
		^super.newCopyArgs(name,ip,port).initRandSync;
	}
	
	/*
	 * Setup all the global things for random syncing.
	 */
	initRandSync {
		
		if (name.isNil, {name = "Default"});
		if (ip.isNil, {ip = "127.0.0.1"});
		if (port.isNil, {port = 57120});
		
		groupAddress = NetAddr(ip,port);
		
		randSyncResponder = OSCresponderNode(nil, '/randSeed', { |t, r, msg|
			this.setRandomSeed(msg[1]);
		}).add;
		
		randomSeed = rrand(1,10000);
		this.setRandomSeed(randomSeed);
		this.broadcastRandomSeed(randomSeed);
	
		this.storeGlobalSynthDefs;

		headGroup = Group.new(Server.default, \addToHead);
		serverRandSeed = Synth(\ServerRandomSeed,["seed", randomSeed], target: headGroup);
	}
	
	/*
	 * Return the current random seed.
	 */
	getRandomSeed {
		^randomSeed;
	}
	
	/*
	 * Set the random seed for the language and server.
	 */
	setRandomSeed {|newSeed|
		randomSeed = newSeed;
		thisThread.randSeed = randomSeed;
		serverRandSeed.set("seed", randomSeed);
		serverRandSeed.set("trig",1);
		serverRandSeed.set("trig",0);
	}
	
	/*
	 * Send the random seed value to the group. This makes that the last person to enter
	 * generate the seed, ensuring that it is truly random and that everyone will have the
	 * same seed.
	 */
	broadcastRandomSeed {
		groupAddress.sendMsg('/randSeed',randomSeed);
	}
	
	/*
	 * Store any SynthDefs needed by this class.
	 */
	storeGlobalSynthDefs {
		
		(
		SynthDef(\ServerRandomSeed, { arg seed=1956, trig=0.0;
			RandSeed.kr(trig, seed);
		}).store;
		);
		
	}
	
	/*
	 * Cleans up things used by this class. Make sure to call super.free from the
	 * subclass's free method to make this happen!
	 */
	free {
		headGroup.deepFree;
		headGroup.free;
		randSyncResponder.free;
	}
	
	/*
	 * Basic SynthDef factory. You tell it the name of the SynthDef and a function containing
	 * all the UGens that make sound. Ensures that all synth made with this contain settable
	 * random number generators, SanityCheck, and Pan2.
	 */
	stdSynthDef {|synthName, function|
		SynthDef(synthName, {|out=0, pan=0, amp=0.3, randID=1|
			var sig;
			
			RandID.kr(randID);
			
			sig = SynthDef.wrap(function);
			
			sig = SanityCheck2.ar(sig);
			
			Out.ar(out, Pan2.ar(sig,pan,amp));
		}).store;
	}
	
	/*
	 * Creates a new Document with a template for making a subclass of NetworkPiece.
	 * You can supply the name of the new class as an argument.
	 */
	*template {|subclassName|
		var template;
		
		if(subclassName.isNil, { subclassName = "DefaultSubclass" });
		if(subclassName.isKindOf(String) == false, { ^"WARNING: New class name must be a String!"; });
		
		template = Document.open(NetworkPiece.filenameSymbol.asString.replace("NetworkPiece.sc","NetworkPieceTemplate.rtf"));
		
		template.string = subclassName + template.string;
		
		template.title = subclassName;
		
		template.syntaxColorize;
	}
}